package top.hcode.hoj.manager.coll;

import cn.hutool.core.util.NumberUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.sagacity.sqltoy.model.MapKit;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import top.hcode.hoj.common.LazyDao;
import top.hcode.hoj.dao.*;
import top.hcode.hoj.pojo.dto.coll.ItechCollJudgeQuestionDTO;
import top.hcode.hoj.pojo.entity.CollQuestionJudgeRecord;
import top.hcode.hoj.pojo.entity.CollUserStat;
import top.hcode.hoj.pojo.entity.coll.CollQuestion;
import top.hcode.hoj.pojo.entity.coll.CollUserAnswer;
import top.hcode.hoj.service.admin.AdminCollUserStatService;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 选择题判分
 *
 * @author orangej
 * @since 2025/2/15
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ItechCollQuestionJudgeManger {
    private final CollQuestionDao questionDao;
    private final CollQuestionOptionDao optionDao;
    private final CollUserAnswerDao answerDao;
    private final CollUserStatDao userStatDao;
    private final CollQuestionJudgeRecordDao judgeRecordDao;
    private final AdminCollUserStatService userStatService;

    private final LazyDao dao;

    /**
     * 主观题判分
     *
     * @param teacherUserId 教师用户id
     * @param dto           主观题判分信息
     */
    @Transactional
    public void judgeSubjective(String teacherUserId, ItechCollJudgeQuestionDTO dto) {
        String questionId = dto.getQuestionId();
        String userAnswerId = dto.getUserAnswerId();
        BigDecimal score = dto.getScore();

        CollUserAnswer userAnswer = answerDao.getById(userAnswerId);
        if (userAnswer == null) {
            throw new IllegalArgumentException("用户答案不存在 userAnswerId:" + userAnswerId);
        }

        CollQuestion question = questionDao.getByIdWithCache(questionId);
        if (question == null) {
            throw new IllegalArgumentException("题目不存在 : " + questionId);
        }

        // score 是否超出题目分值
        if (score.compareTo(BigDecimal.ZERO) < 0) {
            throw new IllegalArgumentException("分数不能小于0");
        }
        if (score.compareTo(question.getScore()) > 0) {
            throw new IllegalArgumentException("本题分值为 " + NumberUtil.toStr(question.getScore()) + " 分，请修改分数");
        }

        // 更新分数
        userAnswer.setScore(score);
        userAnswer.setJudgeState(2);
        answerDao.updateById(userAnswer);

        // 保存评分记录
        CollQuestionJudgeRecord judgeRecord = new CollQuestionJudgeRecord();
        judgeRecord.setUserAnswerId(userAnswerId);
        judgeRecord.setQuestionId(questionId);
        judgeRecord.setUserId(userAnswer.getUserId());
        judgeRecord.setTeacherId(teacherUserId);
        judgeRecord.setScore(score);
        judgeRecordDao.save(judgeRecord);

        // 更新 coll_user_stat 主观题分数
        BigDecimal subjectiveScore = answerDao.fetchSubjectiveScore(userAnswer.getCollId(), userAnswer.getUserId());
        userStatDao.saveSubjectiveScore(userAnswer.getCollId(), userAnswer.getUserId(), subjectiveScore);

        updateUserJudgeStat(userAnswer.getCollId(), userAnswer.getUserId());
    }

    public void updateUserJudgeStat(String collId, String userId) {
//        List<NutMap> statNumMap = dao.queryMap("select judge_state, count(1) as num " +
//                "from coll_user_answer " +
//                "where coll_id = ? and user_id = ? group by judge_state", collId, userId);
//
//        if (statNumMap.size() == 1 && statNumMap.get(0).getInt("judgeState") == 2) {
        // 所有答案都是已评分，则更新用户状态为已评分
        dao.runSql("update coll_user_stat set judge_state = 2 where coll_id = ? and user_id = ?", collId, userId);
//        }
    }

    /**
     * 更新指定活动的客观题分数，目前支持单选题、多选题、填空题
     *
     * @param collId 活动id
     */
    @Transactional
    public void judgeAllObjective(String collId) {
        if (Strings.isBlank(collId)) {
            return;
        }

        // 获取所有客观题的答案，包括单选题、多选题、填空题
        Map<String, String> answerMap = questionDao.queryObjectiveQuestionAnswerMap(collId);

        // 准备更新数据 [{questionId, answer, collId}]
        List<Map<String, Object>> dataList = new ArrayList<>();
        for (String questionId : answerMap.keySet()) {
            Map<String, Object> data = MapKit.startOf("questionId", questionId)
                    .of("answer", answerMap.get(questionId))
                    .endOf("collId", collId);
            dataList.add(data);
        }

        // 批量执行，每道题对应一条sql
        dao.batchUpdate(
                // 更新答对的题目分数
                "update coll_user_answer t0\n" +
                "    left join coll_question t1 on t0.question_id = t1.id\n" +
                "set t0.score = t1.score, t0.judge_state = 2\n" +
                "where t0.question_id = :questionId\n" +
                "  and t0.coll_id = :collId\n" +
                "  and t0.answer = :answer\n ",
                dataList);
        dao.batchUpdate(
                // 更新未答对的题目分数为0
                "update coll_user_answer t0\n" +
                "    left join coll_question t1 on t0.question_id = t1.id\n" +
                "set t0.score = 0, t0.judge_state = 2\n" +
                "where t0.question_id = :questionId\n" +
                "  and t0.coll_id = :collId\n" +
                "  and t0.answer != :answer\n  ",
                dataList);

        // 更新 coll_user_state 表中对应的分值
        Map<String, Object> params = MapKit.map("collId", collId);
        if (!questionDao.isCollHasSubjectiveQuestion(collId)) {
            // 没有主观题，判题完成
            params.put("judgeState", 2);
        }

        dao.runSql("update coll_user_stat t0\n" +
                   "    left join\n" +
                   "    (\n" +
                   "        select user_id, sum(score) as score\n" +
                   "        from coll_user_answer\n" +
                   "        where coll_id = :collId\n" +
                   "          and question_id in (select id from coll_question where coll_id = :collId and question_type in (1,2,3))\n" +
                   "        group by user_id\n" +
                   "    ) t1 on t0.user_id = t1.user_id\n" +
                   "set t0.objective_score = t1.score,\n" +
                   "    t0.total_score = t1.score + t0.subjective_score\n" +
                   "    #[,t0.judge_state = :judgeState]\n  " +
                   "where t0.coll_id = :collId\n" +
                   "  and t1.user_id is not null;", params);
    }
}
